package org.springframework.context.support;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.event.ApplicationContextClosedEvent;
import org.springframework.context.event.ApplicationContextRefreshedEvent;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.core.io.DefaultResourceLoader;

import java.util.Collection;
import java.util.Map;

/**
 * @Name AbstractApplicationContext
 * @Description: 应用上下文 [抽象] 实现类
 * 描述信息：典型的 {模板方法} 设计模式，制定了刷新上下文的统一流程，并实现了公共步骤，个性化的步骤定义为抽象方法，交由子类自己实现。
 * @Version v1.0.0
 * @Author: lichao
 * @Date: 2024-03-19 19:17:44
 **/
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {

    public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";

    private ApplicationEventMulticaster applicationEventMulticaster;

    @Override
    public void refresh() throws BeansException {
        // 刷新 Bean 工厂：创建 BeanFactory 实例，并加载 BeanDefinition 信息
        refreshBeanFactory();
        // 获取 Bean 工厂实例
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        // 添加 ApplicationContext 感知处理器, 让继承自 ApplicationContextAware 接口的 Bean 能感知到其所属的 ApplicationContext 上下文
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
        // 在 Bean 实例化之前，执行 BeanFactoryPostProcessor，修改 BeanDefinition 信息
        invokeBeanFactoryPostProcessors(beanFactory);
        // 注册 BeanPostProcessor（必须在使用者 Bean 之前完成实例化）
        registerBeanPostProcessors(beanFactory);
        // 初始化事件发布者
        initApplicationEventMulticaster();
        // 注册事件监听器
        registerListeners();
        // 提前实例化所有单例 Bean
        beanFactory.preInstantiateSingletons();
        // 发布应用上下文刷新完成事件
        finishRefresh();
    }

    /**
     * 刷新 Bean 工厂：创建 BeanFactory，并加载 BeanDefinition
     *
     * @version v1.0.0
     * @author lichao
     * @date 2024-03-19 19:23:41
     */
    protected abstract void refreshBeanFactory() throws BeansException;

    /**
     * 获取 BeanFactory 实例
     *
     * @return org.springframework.beans.factory.ConfigurableListableBeanFactory 结果
     * @version v1.0.0
     * @author lichao
     * @date 2024-03-19 19:25:09
     */
    protected abstract ConfigurableListableBeanFactory getBeanFactory();

    /**
     * 在 Bean 实例化之前，执行 BeanFactoryPostProcessor，修改 BeanDefinition 信息
     *
     * @param beanFactory
     * @version v1.0.0
     * @author lichao
     * @date 2024-03-19 19:26:44
     */
    protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        Map<String, BeanFactoryPostProcessor> map = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
        for (BeanFactoryPostProcessor beanFactoryPostProcessor : map.values()) {
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        }
    }

    /**
     * 注册 BeanPostProcessor（必须在使用者 Bean 之前完成实例化）
     *
     * @param beanFactory
     * @version v1.0.0
     * @author lichao
     * @date 2024-03-19 19:27:12
     */
    protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        Map<String, BeanPostProcessor> map = beanFactory.getBeansOfType(BeanPostProcessor.class);
        for (BeanPostProcessor beanPostProcessor : map.values()) {
            beanFactory.addBeanPostProcessor(beanPostProcessor);
        }
    }

    /**
     * 初始化事件发布者
     *
     * @version v1.0.0
     * @author lichao
     * @date 2024-03-21 17:12:54
     */
    protected void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.addSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, applicationEventMulticaster);
    }

    /**
     * 注册事件监听器
     *
     * @version v1.0.0
     * @author lichao
     * @date 2024-03-21 17:13:04
     */
    protected void registerListeners() {
        Collection<ApplicationListener> applicationListeners = getBeansOfType(ApplicationListener.class).values();
        for (ApplicationListener applicationListener : applicationListeners) {
            applicationEventMulticaster.addApplicationListener(applicationListener);
        }
    }

    /**
     * 发布应用上下文刷新完成事件
     *
     * @version v1.0.0
     * @author lichao
     * @date 2024-03-21 17:13:16
     */
    protected void finishRefresh() {
        publishEvent(new ApplicationContextRefreshedEvent(this));
    }

    @Override
    public void publishEvent(ApplicationEvent event) {
        applicationEventMulticaster.multicastEvent(event);
    }

    @Override
    public Object getBean(String name) throws BeansException {
        return getBeanFactory().getBean(name);
    }

    @Override
    public <T> T getBean(Class<T> requiredType) throws BeansException {
        return getBeanFactory().getBean(requiredType);
    }

    @Override
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return getBeanFactory().getBean(name, requiredType);
    }

    @Override
    public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
        return getBeanFactory().getBeansOfType(type);
    }

    /**
     * 获取所有已经注册的 BeanDefinition 信息的名称
     *
     * @return java.lang.String[] 结果
     * @version v1.0.0
     * @author lichao
     * @date 2024-03-20 15:47:51
     */
    public String[] getBeanDefinitionNames() {
        return getBeanFactory().getBeanDefinitionNames();
    }

    /**
     * 自动关闭上下文
     * 说明: 为了确保上下文销毁方法在虚拟机关闭之前执行，需要向虚拟机中注册一个钩子方法
     * 注意: 非 web 应用不生效
     *
     * @version v1.0.0
     * @author lichao
     * @date 2024-03-20 15:56:18
     */
    public void registerShutdownHook() {
        Thread shutdownHook = new Thread() {
            @Override
            public void run() {
                doClose();
            }
        };
        Runtime.getRuntime().addShutdownHook(shutdownHook);
    }

    /**
     * 手动关闭上下文, 销毁资源
     *
     * @version v1.0.0
     * @author lichao
     * @date 2024-03-20 15:47:38
     */
    public void close() {
        doClose();
    }

    /**
     * 执行关闭上下文的动作, 销毁资源
     *
     * @version v1.0.0
     * @author lichao
     * @date 2024-03-20 15:47:38
     */
    protected void doClose() {
        // 发布应用上下文关闭事件
        publishEvent(new ApplicationContextClosedEvent(this));
        // 销毁应用上下文内所有的单例 Bean 实例
        destroyBeans();
    }

    /**
     * 销毁上下文容器中的 Bean 实例
     *
     * @version v1.0.0
     * @author lichao
     * @date 2024-03-20 15:55:25
     */
    protected void destroyBeans() {
        getBeanFactory().destroySingletons();
    }


}

